using System;
using UnityEngine;
using GameFramework;
using GameFramework.DataNode;
using UnityGameFramework.Runtime;
using LS.Event;

namespace LS
{
    public static class DataNodeExtensions
    {
        public static T CreateDataNode<T>(this DataNodeComponent component, string path)
        {
            return default;
        }
        public static void SetString(this DataNodeComponent component, string path, string value)
        {
            component.SetData(path, value);
            SetData(component, path, value);
        }
        
        public static void SetInt(this DataNodeComponent component, string path, int value)
        {
            SetData(component, path, value);
        }
        
        public static void SetFloat(this DataNodeComponent component, string path, float value)
        {
            SetData(component, path, value);
        }
        
        public static void SetBool(this DataNodeComponent component, string path, bool value)
        {
            SetData(component, path, value);
        }
        
        public static void SetVector2(this DataNodeComponent component, string path, Vector2 value)
        {
            SetData(component, path, value);
        }
        
        public static void SetVector3(this DataNodeComponent component, string path, Vector3 value)
        {
            SetData(component, path, value);
        }
        
        public static void SetVector4(this DataNodeComponent component, string path, Vector4 value)
        {
            SetData(component, path, value);
        }
                
        public static void SetQuaternion(this DataNodeComponent component, string path, Quaternion value)
        {
            SetData(component, path, value);
        }
        
        public static void SetColor(this DataNodeComponent component, string path, Color value)
        {
            SetData(component, path, value);
        }

        public static void SetColor32(this DataNodeComponent component, string path, Color32 value)
        {
            SetData(component, path, value);
        }
        
        public static void RemoveData(this DataNodeComponent component, string path, bool removeNode = false)
        {
            if (removeNode)
            {
                component.RemoveNode(path);
            }
            else
            {
                var node = component.GetNode(path);
                if (node != null)
                    node.SetData(null);
            }
        }

        public static void SetData<T>(this DataNodeComponent component, string path, T value)
        {
            IDataNode node = component.GetNode(path);
            Variable oldValue = node?.GetData();
            if (oldValue != null)
            {
                if (oldValue.Type == value.GetType() && value.Equals(oldValue.GetValue()))
                    return;
                
                oldValue = VariableUtil.Create(oldValue.GetValue());
            }

            Variable newValue = null;
            
            if (value is Variable variable)
                newValue = variable;
            else
                newValue = VariableUtil.Create(value);
            
            component.SetData(path, newValue);
            LSEntry.Event.FireNow<DataNodeChangedEventArgs>(component, arg =>
            {
                arg.NodeName = path;
                arg.NewValue = newValue;
                arg.OldValue = oldValue;
            });
        }
        
        public static void SetDataWithoutEvent<T>(this DataNodeComponent component, string path, T value)
        {
            Variable newValue = VariableUtil.Create(value);
            component.SetData(path, newValue);
        }

        public static bool TryGetData<T>(this DataNodeComponent component, string path, out T value)
        {
            IDataNode node = component.GetNode(path);
            value = default;
            
            if (node == null) return false;
            
            Variable variable = node.GetData();
            if (variable == null) return false;
            
            object data = variable.GetValue();
            if (data is not T) return false;
            
            value = (T)data;
            return true;
        }
    }
}
